package org.groupg.practice.data.master;

import it.unimi.dsi.fastutil.bytes.ByteArrayList;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;

/**
 * 针对超密集数据的位级压缩存储
 * 假设数据模式：大部分字段可以用更小的数据类型表示
 */
public class BitPackedDataStore {
    private final int recordCount;

    // 使用最紧凑的数据类型
    private final byte[] idBytes;          // 如果ID在0-255范围内
    private final short[] idShorts;        // 如果ID在0-65535范围内
    private final int[] idInts;            // 完整的int ID

    private final int[] timestamps;        // 时间戳可以用int存储相对值
    private final float[] values;          // 用float代替double，节省50%
    private final short[] labelCodes;      // 标签字典编码

    // 字典压缩
    private final String[] labelDictionary;
    private final Object2IntOpenHashMap<String> labelToCode;

    // 基准时间戳，用于存储相对值
    private final long baseTimestamp;

    public BitPackedDataStore(int capacity, long baseTimestamp) {
        this.recordCount = capacity;
        this.baseTimestamp = baseTimestamp;

        // 根据数据范围选择最合适的数据类型
        if (capacity <= 256) {
            this.idBytes = new byte[capacity];
            this.idShorts = null;
            this.idInts = null;
        } else if (capacity <= 65536) {
            this.idBytes = null;
            this.idShorts = new short[capacity];
            this.idInts = null;
        } else {
            this.idBytes = null;
            this.idShorts = null;
            this.idInts = new int[capacity];
        }

        this.timestamps = new int[capacity];  // 存储相对于baseTimestamp的秒数
        this.values = new float[capacity];    // 用float节省空间
        this.labelCodes = new short[capacity]; // 支持最多65536个不同标签

        this.labelDictionary = new String[65536];
        this.labelToCode = new Object2IntOpenHashMap<>();
        this.labelToCode.defaultReturnValue(-1);
    }

    public void addRecord(int index, int id, long timestamp, double value, String label) {
        // ID存储 - 根据范围选择适当类型
        if (idBytes != null) {
            idBytes[index] = (byte) id;
        } else if (idShorts != null) {
            idShorts[index] = (short) id;
        } else {
            idInts[index] = id;
        }

        // 时间戳存储为相对秒数
        timestamps[index] = (int) ((timestamp - baseTimestamp) / 1000);

        // 值存储为float
        values[index] = (float) value;

        // 标签字典编码
        int code = labelToCode.getInt(label);
        if (code == -1) {
            code = labelToCode.size();
            labelToCode.put(label, code);
            labelDictionary[code] = label;
        }
        labelCodes[index] = (short) code;
    }

    public int getId(int index) {
        if (idBytes != null) return idBytes[index] & 0xFF;
        if (idShorts != null) return idShorts[index] & 0xFFFF;
        return idInts[index];
    }

    public long getTimestamp(int index) {
        return baseTimestamp + (long) timestamps[index] * 1000;
    }

    public double getValue(int index) {
        return values[index];
    }

    public String getLabel(int index) {
        return labelDictionary[labelCodes[index] & 0xFFFF];
    }

    /**
     * 计算精确内存占用
     */
    public long calculateMemoryUsage() {
        long total = 0;

        // 数组内存计算
        if (idBytes != null) total += idBytes.length;
        if (idShorts != null) total += idShorts.length * 2L;
        if (idInts != null) total += idInts.length * 4L;

        total += timestamps.length * 4L;
        total += values.length * 4L;
        total += labelCodes.length * 2L;

        // 字典内存估算
        total += labelToCode.size() * 40L; // 估算每个字典条目40字节
        for (int i = 0; i < labelToCode.size(); i++) {
            if (labelDictionary[i] != null) {
                total += labelDictionary[i].length() * 2L + 40; // 字符串内存
            }
        }

        // 对象头和其他开销
        total += 100; // 固定开销

        return total;
    }
}